# ranking_service.py
import redis
from django.conf import settings
from django.db import transaction
from points.models import UserPoints, User  # 修改导入路径

class RankingService:
    """用户排名服务类"""

    def __init__(self):
        self.r = redis.Redis(
            host=settings.REDIS_HOST,
            port=settings.REDIS_PORT,
            db=settings.REDIS_RANKING_DB,
            password=settings.REDIS_PASSWORD,
            decode_responses=True  # 自动解码为字符串
        )
        self.key = "user_ranking"

    def update_points(self, user_id, points, reason=""):
        """更新用户积分并记录明细（原子操作）"""
        with transaction.atomic():
            # 更新 Redis 分数
            self.r.zincrby(self.key, points, user_id)

            # 记录 MySQL 积分明细
            try:
                user = User.objects.get(id=user_id)
                UserPoints.objects.create(
                    username=user,
                    points=points,
                    reason=reason or f"系统自动更新积分 ({points})"
                )
            except User.DoesNotExist:
                pass

    def batch_update_points(self, point_updates, reason=""):
        """批量更新用户积分"""
        with transaction.atomic():
            pipeline = self.r.pipeline()

            # 批量更新 Redis
            for user_id, points in point_updates.items():
                pipeline.zincrby(self.key, points, user_id)

            pipeline.execute()

            # 批量创建 MySQL 记录
            records = []
            for user_id, points in point_updates.items():
                try:
                    user = User.objects.get(id=user_id)
                    records.append(
                        UserPoints(
                            username=user,
                            points=points,
                            reason=reason
                        )
                    )
                except User.DoesNotExist:
                    pass
            UserPoints.objects.bulk_create(records)

    def get_rank(self, user_id):
        """获取用户排名（1-based）"""
        rank = self.r.zrevrank(self.key, user_id)
        return rank + 1 if rank is not None else None

    def get_score(self, user_id):
        """获取用户积分"""
        return self.r.zscore(self.key, user_id)

    def get_top_users(self, n=100):
        """获取排名前n的用户"""
        return self.r.zrevrange(self.key, 0, n - 1, withscores=True)

    def get_user_count(self):
        """获取参与排名的用户总数"""
        return self.r.zcard(self.key)

    def reset_ranking(self):
        """重置排行榜"""
        self.r.delete(self.key)